
#ifndef _TTG_DEVICES_MAPS_INTERNAL_MAP_
#define _TTG_DEVICES_MAPS_INTERNAL_MAP_
#include "Common/Definitions.h"

#include <vector>
#include "Common/Structures.h"

namespace ttg_internal
{
	namespace devices
	{
		//Universal enumerator for InternalMap.
		template <class T>
		class InternalMapEnumerator :public ttg::structures::Enumerator<T>
		{
			private:
				std::vector<std::pair<T, bool> > *values;	//as {value + is_assigned}.
				size_t cur;
				bool is_first_call;
				//Finds next assigned value.
				//In case of end of collection, returns false.
				inline bool findNext()
				{
					for (; cur < values->size(); cur++)
					{
						if ((*values)[cur].second)
						{
							return true;
						}
					}
					return false;
				}
			public:
				//Creates reseted enumerator for required values.
				inline InternalMapEnumerator(std::vector<std::pair<T, bool> > *values)
				{
					this->values = values;
					cur = 0;
					is_first_call = true;
				}
				//Enumerator<T> member.
				//Moves to next element. If there aren't any, returns false.
				virtual bool moveNext()
				{
					if (!is_first_call)
					{
						cur += 1;
						return findNext();
					}
					else
					{
						is_first_call = false;
						return findNext();
					}
				}
				//Enumerator<T> member.
				//Returns current element.
				virtual T &current()
				{
					return (*values)[cur].first;
				}
				//Enumerator<T> member.
				//Resets enumerator to initial state.
				virtual void reset()
				{
					cur = 0;
					is_first_call = true;
				}
		};
		//Collection, that maps APIs or devices to arbitrary values.
		template <class T, class INDEX>
		class InternalMap :public ttg::structures::EnumerableCollection<T>
		{
			private:
				std::vector<std::pair<T, bool> > values;	//as {value + is_assigned}.
				//Checks size and [optionally] resizes collection.
				inline void checkSize(INDEX id)
				{
					if ((size_t)id >= values.size())
					{
						size_t old_size = values.size();
						values.resize((size_t)id + 1);
						for (size_t i = old_size; i < values.size(); i++)
							values[i].second = false;
					}
				}
				//Registers required ID. Can be called for already registered IDs.
				inline void reg(INDEX id)
				{
					checkSize(id);
					values[(size_t)id].second = true;
				}
			public:
				//Returns required element.
				//If such element does not exist, creates a new record.
				inline T &operator [](INDEX id)
				{ reg(id); return values[(size_t)id].first; }
				//Clears all registered values.
				inline void clear()
				{ values.clear(); }
				//Returns true, if required API was registered.
				inline bool isContained(INDEX id)
				{ checkSize(id); return values[(size_t)id].second; }
				//Returns all indices, that were registered.
				inline std::vector<INDEX> getIndices()
				{
					std::vector<INDEX> res;
					for (size_t i = 0; i < values.size(); i++)
						if (values[i].second)
							res.push_back((INDEX)i);
					return res;
				}
				//EnumerableCollection<T> member.
				//Returns enumerator for current collection.
				virtual ttg::structures::Enumerator<T> *getEnumerator()
				{ return new InternalMapEnumerator<T>(&values); }
		};
	}
}

#endif
